import * as events from 'events';
import * as net from 'net';

/** 客户端对象池 */
interface Clients {
    [index: string]: net.Socket;
}

/** 订阅者对象池 */
interface Subscriptions {
    [index: string]: (id: string, msg: string) => void;
}

/** 事件频道，相当于消息总线 */
const channel = new events.EventEmitter();
const clients: Clients = {};
const subscriptions: Subscriptions = {};

channel.setMaxListeners(10);

channel.on('join', function (id: string, client: net.Socket) {
    console.log(`${id} join the chatroom`);
    const welcome = `
        Welcome!
            Guests online: ${channel.listeners('broadcast').length}
    `;
    client.write(`${welcome}\n`);

    clients[id] = client;
    subscriptions[id] = (senderId, message) => {
        if (id !== senderId) {
            clients[id].write(message);
        }
    };

    channel.on('broadcast', subscriptions[id]);

    channel.on('leave', function (leaveId: string) {
        if (id !== leaveId) return;

        channel.removeListener('broadcast', subscriptions[id]);
        channel.emit('broadcast', id, `${id} has left the chatroom.\n`);
        console.log(`${id} left the chatroom`);
    });
});

channel.on('shutdown', () => {
    channel.emit('broadcast', '', 'The server has shut down.\n');
    channel.removeAllListeners('broadcast');
});

const server = net.createServer((client) => {
    const id = `${client.remoteAddress}:${client.remotePort}`;
    channel.emit('join', id, client);

    client.on('data', (data) => {
        const str = data.toString();
        if (str === 'shutdown\r\n') {
            channel.emit('shutdown');
        }

        channel.emit('broadcast', id, str);
    });

    client.on('close', () => {
        channel.emit('leave', id);
    });
});

server.listen(8888);
console.log('server running on 127.0.0.1:8888');
